--- /dev/null
+// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
+
+const Clutter = imports.gi.Clutter;
+const Gio = imports.gi.Gio;
+const GObject = imports.gi.GObject;
+const Lang = imports.lang;
+const Meta = imports.gi.Meta;
+const Shell = imports.gi.Shell;
+
+const Dialog = imports.ui.dialog;
+const Main = imports.ui.main;
+const Tweener = imports.ui.tweener;
+
+const FROZEN_WINDOW_BRIGHTNESS = -0.3
+const DIALOG_TRANSITION_TIME = 0.15
+
+const CloseDialog = new Lang.Class({
+ Name: 'CloseDialog',
+ Extends: GObject.Object,
+ Implements: [ Meta.CloseDialog ],
+ Properties: {
+ 'window': GObject.ParamSpec.override('window', Meta.CloseDialog)
+ },
+
+ _init: function (window) {
+ this.parent();
+ this._window = window;
+ this._dialog = null;
+ },
+
+ get window() {
+ return this._window;
+ },
+
+ set window(window) {
+ this._window = window;
+ },
+
+ _createDialogContent: function () {
+ let tracker = Shell.WindowTracker.get_default();
+ let windowApp = tracker.get_window_app(this._window);
+
+ /* Translators: %s is an application name */
+ let title = _("ā%sā is not responding.").format(windowApp.get_name());
+ let subtitle = _("You may choose to wait a short while for it to " +
+ "continue or force the application to quit entirely.");
+ let icon = new Gio.ThemedIcon({ name: 'dialog-warning-symbolic' });
+ return new Dialog.MessageDialogContent({ icon, title, subtitle });
+ },
+
+ _initDialog: function () {
+ if (this._dialog)
+ return;
+
+ let windowActor = this._window.get_compositor_private();
+ this._dialog = new Dialog.Dialog(windowActor, 'close-dialog');
+ this._dialog.width = windowActor.width;
+ this._dialog.height = windowActor.height;
+
+ this._dialog.addContent(this._createDialogContent());
+ this._dialog.addButton({ label: _('Force Quit'),
+ action: Lang.bind(this, this._onClose),
+ default: true });
+ this._dialog.addButton({ label: _('Wait'),
+ action: Lang.bind(this, this._onWait),
+ key: Clutter.Escape });
+
+ global.focus_manager.add_group(this._dialog);
+ },
+
+ _addWindowEffect: function () {
+ // We set the effect on the surface actor, so the dialog itself
+ // (which is a child of the MetaWindowActor) does not get the
+ // effect applied itself.
+ let windowActor = this._window.get_compositor_private();
+ let surfaceActor = windowActor.get_first_child();
+ let effect = new Clutter.BrightnessContrastEffect();
+ effect.set_brightness(FROZEN_WINDOW_BRIGHTNESS);
+ surfaceActor.add_effect_with_name("gnome-shell-frozen-window", effect);
+ },
+
+ _removeWindowEffect: function () {
+ let windowActor = this._window.get_compositor_private();
+ let surfaceActor = windowActor.get_first_child();
+ surfaceActor.remove_effect_by_name("gnome-shell-frozen-window");
+ },
+
+ _onWait: function () {
+ this.response(Meta.CloseDialogResponse.WAIT);
+ },
+
+ _onClose: function () {
+ this.response(Meta.CloseDialogResponse.FORCE_CLOSE);
+ },
+
+ vfunc_show: function () {
+ if (this._dialog != null)
+ return;
+
+ this._addWindowEffect();
+ this._initDialog();
+
+ this._dialog.scale_y = 0;
+ this._dialog.set_pivot_point(0.5, 0.5);
+
+ Tweener.addTween(this._dialog,
+ { scale_y: 1,
+ transition: 'linear',
+ time: DIALOG_TRANSITION_TIME,
+ onComplete: Lang.bind(this, function () {
+ Main.layoutManager.trackChrome(this._dialog, { affectsInputRegion: true });
+ })
+ });
+ },
+
+ vfunc_hide: function () {
+ if (this._dialog == null)
+ return;
+
+ let dialog = this._dialog;
+ this._dialog = null;
+ this._removeWindowEffect();
+
+ Tweener.addTween(dialog,
+ { scale_y: 0,
+ transition: 'linear',
+ time: DIALOG_TRANSITION_TIME,
+ onComplete: Lang.bind(this, function () {
+ dialog.destroy();
+ })
+ });
+ },
+
+ vfunc_focus: function () {
+ if (this._dialog)
+ this._dialog.grab_key_focus();
+ }
+});
const WindowMenu = imports.ui.windowMenu;
const PadOsd = imports.ui.padOsd;
const EdgeDragAction = imports.ui.edgeDragAction;
+const CloseDialog = imports.ui.closeDialog;
const SHELL_KEYBINDINGS_SCHEMA = 'org.gnome.shell.keybindings';
const MINIMIZE_WINDOW_ANIMATION_TIME = 0.2;
this._shellwm.connect('destroy', Lang.bind(this, this._destroyWindow));
this._shellwm.connect('filter-keybinding', Lang.bind(this, this._filterKeybinding));
this._shellwm.connect('confirm-display-change', Lang.bind(this, this._confirmDisplayChange));
+ this._shellwm.connect('create-close-dialog', Lang.bind(this, this._createCloseDialog));
global.screen.connect('restacked', Lang.bind(this, this._syncStacking));
this._workspaceSwitcherPopup = null;
dialog.open();
},
+ _createCloseDialog: function (shellwm, window) {
+ return new CloseDialog.CloseDialog(window);
+ },
+
_showResizePopup: function(display, show, rect, displayW, displayH) {
if (show) {
if (!this._resizePopup)
SHOW_WINDOW_MENU,
FILTER_KEYBINDING,
CONFIRM_DISPLAY_CHANGE,
+ CREATE_CLOSE_DIALOG,
LAST_SIGNAL
};
0,
NULL, NULL, NULL,
G_TYPE_NONE, 0);
+ /**
+ * ShellWM::create-close-dialog:
+ * @wm: The WM
+ * @window: The window to create the dialog for
+ *
+ * Creates a close dialog for the given window.
+ *
+ * Returns: (transfer full): The close dialog instance.
+ */
+ shell_wm_signals[CREATE_CLOSE_DIALOG] =
+ g_signal_new ("create-close-dialog",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL, NULL,
+ META_TYPE_CLOSE_DIALOG, 1, META_TYPE_WINDOW);
}
void
g_signal_emit (wm, shell_wm_signals[CONFIRM_DISPLAY_CHANGE], 0);
}
+MetaCloseDialog *
+_shell_wm_create_close_dialog (ShellWM *wm,
+ MetaWindow *window)
+{
+ MetaCloseDialog *dialog;
+
+ g_signal_emit (wm, shell_wm_signals[CREATE_CLOSE_DIALOG], 0, window, &dialog);
+
+ return dialog;
+}
+
/**
* shell_wm_new:
* @plugin: the #MetaPlugin